/*
* Copyright (C) 2020 ~ 2024 chaigec All Rights Reserved.
*
* Author:     chaigec <chaigec@163.com>
* Maintainer: chaigec <chaigec@163.com>

 * Use of this source code is governed by MIT license that can be found in the
 * LICENSE file in the root of the source tree. All contributing project authors
 * may be found in the AUTHORS file in the root of the source tree.
*/

#include "MkRtspPlayer.h"
#include "MkRtspSubSession.h"
#include "MkRtspHeader.h"
#include "MkRtp/MkRtpUdpServer.h"
#include "MkSdp/MkSdp.h"
#include "MkRtp/MkRtpServerPool.h"
#include "MkUtil/MkLog.h"
#include "MkUtil/MkUtil.h"

CMkRtspPlayer::CMkRtspPlayer(CMkEvent* pEvent, CMkTimer* pTimer, MkVector<CMkRtpUdpServer*>& VecRtpUdpServer, const MkEventRemovedCallback& RemovedCb)
    : CMkRtspClient(pEvent, pTimer, VecRtpUdpServer, RemovedCb)
    , CMkRtspStreamSource(MkMediaSourceRtspPlayer)
{

}

Uint32 CMkRtspPlayer::Play(const MkString& RtspUrl, BOOL bStreamTcp, const MkSourceResultCallback& ResultCb, const MkEsPacketCallback& EsCb/* = nullptr*/)
{
    CMkMediaSource::StartMediaSource(ResultCb, EsCb);
    m_bStreamTcp = bStreamTcp;
    return ConnectRtspUrl(RtspUrl);
}

Uint32 CMkRtspPlayer::Pause()
{
    return SendPause();
}

Uint32 CMkRtspPlayer::Recovery()
{
    MkMap<MkRtspHeaderType, MkString> MapHeaders;
    MapHeaders[MkRtspHeaderRange] = "ntp=now-";
    return SendRtspRequest(GetUrl(), MkRtspMethodPlay, MapHeaders);
}

Uint32 CMkRtspPlayer::SetSpeed(float fSpeed)
{
    MkMap<MkRtspHeaderType, MkString> MapHeaders;
    MapHeaders[MkRtspHeaderScale] = std::to_string(fSpeed);
    return SendRtspRequest(GetUrl(), MkRtspMethodPlay, MapHeaders);
}

Uint32 CMkRtspPlayer::Seek(Uint32 uSecond)
{
    MkMap<MkRtspHeaderType, MkString> MapHeaders;
    MapHeaders[MkRtspHeaderRange] = "ntp=" + std::to_string(uSecond) + "-";
    return SendRtspRequest(GetUrl(), MkRtspMethodPlay, MapHeaders);
}

Uint32 CMkRtspPlayer::PlayControl(const MkPlaybackControlType& ControlType, float fSpeed, Uint32 offsetSec)
{
    Uint32 ErrorCode = NoneError;
    switch (ControlType) {
    case MkControlUnknown:
        break;
    case MkControlPause:
        ErrorCode = Pause();
        break;
    case MkControlSeek:
        ErrorCode = Seek(offsetSec);
        break;
    case MkControlSetSpeed:
        ErrorCode = SetSpeed(fSpeed);
        break;
    case MkControlRecovery:
        ErrorCode = Recovery();
        break;
    default:
        break;
    }
    return ErrorCode;
}

Uint32 CMkRtspPlayer::StopMediaSource()
{
    return SendTearDown();
}

Uint32 CMkRtspPlayer::OnRtpPacket(const MkCodecType& Codec, const CMkRtpPacket& RtpPacket, const MkString& Host, Uint16 Port)
{
    MkCodecType CurCodec = Codec;
    if (MkCodecUnknown == Codec) {
        MkUnorderedMap<Uint32, CMkRtspSubSession*>::iterator it = m_MapSession.begin();
        for (; it != m_MapSession.end(); it++) {
            if (RtpPacket.GetSsrc() == it->second->GetSsrc()) {
                CurCodec = (MkCodecType)it->first;
                break;
            }
        }
    }
    switch (CurCodec) {
    case MkCodecH264:
        ParseH264RtpPacket(RtpPacket);
        break;
    case MkCodecH265:
        ParseH265RtpPacket(RtpPacket);
        break;
    case MkCodecAac:
        ParseAacRtpPacket(RtpPacket);
        break;
    default:
        break;
    }
    return NoneError;
}

Uint32 CMkRtspPlayer::OnRtcpPacket(const CMkRtcpPacket& RtcpPacket, const MkString& Host, Uint16 Port)
{
    return NoneError;
}

Uint32 CMkRtspPlayer::OnResponseError(const MkRtspStatusCode& StatusCode)
{
    if (m_ResultCb) {
        m_ResultCb(this, RtspResponseErrorBegin + StatusCode);
        m_ResultCb = nullptr;
    }
    return CMkRtspClient::OnResponseError(StatusCode);
}

Uint32 CMkRtspPlayer::OnOptionResponse(const CMkRtspResponse& Res)
{
    if (NoneError == CMkRtspClient::OnOptionResponse(Res) && GetPlaySession().empty()) {
        SendDescribe();
    }
    return NoneError;
}

Uint32 CMkRtspPlayer::OnDescribeResponse(const CMkRtspRequest& RtspReq, const CMkRtspResponse& Res)
{
    Uint32 ErrorCode = NoneError;
    const MkString Authenticate = Res.GetHeader(MkRtspHeaderWWWAuthenticate);
    if (MkRtspStateUnauthorized == Res.GetStatusCode()) {
        return SendDescribe();
    }
    CMkSdp Sdp;
    ErrorCode = Sdp.ParseContent(Res.GetBody());
    MkCheckErrorLog(ErrorCode, "parse sdp:%s failed\n", Res.GetBody().c_str());

    MkString RtpHost = Sdp.GetConnection().GetAddr();

    if (RtpHost.empty()
        || "0.0.0.0" == RtpHost
        || "127.0.0.1" == RtpHost) {
        RtpHost = Sdp.GetOrigin().GetAddr();
        if (RtpHost.empty()
            || "0.0.0.0" == RtpHost
            || "127.0.0.1" == RtpHost) {
            RtpHost = GetRemoteHost();
        }
    }

    MkVector<CMkSdpMedia>::const_iterator it = Sdp.GetMedia().begin();
    for (; it != Sdp.GetMedia().end(); it++) {
        CMkRtspSubSession *pSubSession = new CMkRtspSubSession(RtpHost, [this](const CMkVideoParam& VideoParam, const CMkAudioParam& AudioParam) {
            if (MkCodecUnknown != VideoParam.GetCodec()) {
                m_VideoParam = VideoParam;
            }
            if (MkCodecUnknown != AudioParam.GetCodec()) {
                m_AudioParam = AudioParam;
            }
        });
        if (!pSubSession) {
            return MallocFailed;
        }
        pSubSession->SetSdpMedia(*it);
        if (!m_bStreamTcp) {
            pSubSession->SetRtpUdpServer(GetFreeRtpUdpServer());
        }
        m_MapSession[pSubSession->GetCodec()] = pSubSession;
    }
    if (!m_MapSession.empty()) {
        SendSetup(m_MapSession.begin()->second, "play");
    }
    return NoneError;
}

Uint32 CMkRtspPlayer::OnSetupResponse(const CMkRtspRequest&  RtspReq, const CMkRtspResponse& Res)
{
    Uint32 ErrorCode = CMkRtspClient::OnSetupResponse(RtspReq, Res);
    if (NoneError == ErrorCode) {
        ErrorCode = SendPlay();
    }
    return ErrorCode;
}

Uint32 CMkRtspPlayer::OnPlayResponse(const CMkRtspResponse& Res)
{
    if (m_ResultCb) {
        m_ResultCb(this, NoneError);
        m_ResultCb = nullptr;
    }
    return CMkRtspClient::OnPlayResponse(Res);
}

Uint32 CMkRtspPlayer::OnTearDownResponse(const CMkRtspResponse& Res)
{
    CMkRtspClient::OnTearDownResponse(Res);
    Close();
    return SocketClosed;
}

Uint32 CMkRtspPlayer::OnClose()
{
    if (m_ResultCb) {
        m_ResultCb(this, SocketConnectFailed);
        m_ResultCb = nullptr;
    }
    return CMkRtspClient::OnClose();
}

CMkRtspPlayer::~CMkRtspPlayer()
{
}